#ifndef __LZJLEX_CPP__
#define __LZJLEX_CPP__

#include "utils.cpp"
#include "globals.cpp"
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>

using std::cin;
using std::cout;
using std::endl;
using std::stringstream;

// #define DEBUG
#ifdef DEBUG
#define DB(a, b) cout << a << " " << b << endl;
#else
#define DB(a, b) ;
#endif

// 用于将控制台输出流tee到文件中，但如果目标输出也是控制台，就不tee
#define REDIRECT(cout, sout, content)\
    cout << content;         \
    if (&cout != &sout)        \
        sout << content;


// 程序入口
void lzjlex(std::istream&, std::ostream&);

// 在一行内处理
static bool analyzeLine(const string&, int, std::ostream&);

// 判断遇最后的换行是否合法（有没有把未完成的单词截断）
static bool isLegalLinebreak(StateType);

// 正确完成一个单词
static void onDone(Token &, std::ostream &);

// 出错
static void onError(Token&, std::ostream&, string, int, int);



void lzjlex(std::istream &sin, std::ostream &sout) {
    int linePos = 0;
    string lineStr;
    while (std::getline(sin, lineStr)) {
        DB("Getline>", lineStr);
        linePos++;
        analyzeLine(lineStr, linePos, sout);
    }
}

static bool analyzeLine(const string& line, int linePos, std::ostream &sout){
    char ch;
    int charPos = 0;
    Token result;
    StateType state = StateType::START;
    bool fake = false;
    for (; charPos < line.length(); ++charPos) {
        ch = line.at(charPos);
        fake = false;
        DB("  >", ch);
        if (state != StateType::DONE && state != StateType::ERROR) {
            result.word += ch;
            switch (state) {
            case StateType::START:
                if (isOneWordOperator(ch)) { // 单目运算符直接Done
                    result.token = getOperatorType(ch);
                    fake = true;
                    state = StateType::DONE;
                } else if(ch == '<') {
                    result.token = TokenType::LSHIFT;
                    state = StateType::LT;
                } else if (ch == '>') {
                    result.token = TokenType::RSHIFT;
                    state = StateType::GT;
                } else if (isalpha(ch)) {
                    result.token = TokenType::ID;
                    state = StateType::ID_DIGIT;
                } else if (ch == '0') {
                    result.token = TokenType::INTEGER;
                    state = StateType::DIG_ZERO;
                } else if ('1' <= ch && ch <= '9') {
                    result.token = TokenType::INTEGER;
                    state = StateType::DIG_DIGIT;
                } else if (ch == '\"') {
                    result.token = TokenType::STRING;
                    state = StateType::STR_CHAR;
                } else if (ch == ' ') {
                    state = StateType::START;
                    result.word.pop_back();
                } else {
                    state = StateType::ERROR;
                }
                break;
            case StateType::ID_LETTER: // 这两个状态是类似的
            case StateType::ID_DIGIT:  // 这两个状态是类似的
                if (isalpha(ch)) {
                    state = StateType::ID_LETTER;
                } else if(ch == '_'){
                    state = StateType::ID_UNDERLINE;
                } else if(isdigit(ch)){
                    state = StateType::ID_DIGIT;
                } else{
                    state = StateType::DONE;
                }
                break;
            case StateType::ID_UNDERLINE:
                if(isalpha(ch)){
                    state = StateType::ID_LETTER;
                } else if(isdigit(ch)){
                    state = StateType::ID_DIGIT;
                } else{
                    state = StateType::ERROR;
                }
                break;
            case StateType::DIG_ZERO:
                if(ch == 'l' || ch == 'L'){
                    fake = true;
                } 
                state = StateType::DONE;
                break;
            case StateType::DIG_DIGIT:
                if(isdigit(ch)){
                    // same state
                } else if(ch == 'l' || ch == 'L'){
                    fake = true;
                    state = StateType::DONE;
                } else {
                    state = StateType::DONE;
                }
                break;
            case StateType::STR_CHAR:
                if(ch == '\\'){
                    result.word.pop_back();
                    state = StateType::STR_ESCAPE;
                } else if(ch == '\"'){
                    fake = true;
                    state = StateType::DONE;
                } else {
                    // same state
                }
                break;
            case StateType::STR_ESCAPE:
                if(isEscape(ch)){
                    result.word.pop_back();
                    result.word.append(toEscape(ch));
                    state = StateType::STR_CHAR;
                } else {
                    state = StateType::ERROR;
                }
                break;
            case StateType::LT:
                if(ch == '<'){
                    fake = true;
                    state = StateType::DONE;
                } else {
                    state = StateType::ERROR;
                }
                break;
            case StateType::GT:
                if (ch == '>') {
                    fake = true;
                    state = StateType::DONE;
                } else {
                    state = StateType::ERROR;
                }
                break;
            default: // shall never reach
                cout << "Miss a case！！！\n";
                return false;
            }
        } 
        if (state == StateType::DONE){
            if(!fake){
                charPos--;
                result.word.pop_back();
            }
            state = StateType::START;
            onDone(result, sout);
        } else if(state == StateType::ERROR){
            onError(result, sout, line, linePos, charPos);
            return false;
        }
    } // end input while loop
    if(isLegalLinebreak(state)){
        if(!fake && state != StateType::START){ // 没有fake
            onDone(result, sout);
        }
    } else {
        onError(result, sout, line, linePos, charPos);
        cout << "[Error] Line "<<linePos << ": Unexpected line break" << endl;
        return false;
    }
    sout << endl;
    return true;
}

static void onError(Token& result, std::ostream& sout, string line, int linePos, int charPos) {
    string prefix = "[Error] Line " + std::to_string(linePos) + "(" + std::to_string(charPos) + "): ";
    REDIRECT(cout, sout,
             endl << prefix << "Word (" << result.word << ") is an illegal "
                  << getTokenLiteral(result.token) << endl;);
    string prespace = " ";
    for (int i = 0; i < prefix.length() - 1; ++i){
        prespace += " ";
    }
    REDIRECT(cout, sout, prespace << line << endl << prespace);
    for (int i = 0; i < charPos - result.word.length();++i){
        REDIRECT(cout, sout, " ");
    }
    for (int i = 0; i < result.word.length() - 1; ++i) {
        REDIRECT(cout, sout, "~");
    }
    REDIRECT(cout, sout, "^\n\n");
}


static void onDone(Token& result, std::ostream& sout){
    if (result.token == TokenType::ID) { // 判断是否是关键字
        result.token = getKeywordType(result.word);
    }
    sout << getTokenLiteral(result.token);
    if (result.token == TokenType::INTEGER || result.token == TokenType::STRING ||
        result.token == TokenType::ID) {
        sout << "(" << result.word << ")";
    }
    if(result.token == TokenType::INTEGER){
        result.num = std::stoi(result.word);
    }
    result.word.clear();
    sout << "  ";
}


static bool isLegalLinebreak(StateType state){
    return state == StateType::START 
            || state == StateType::DONE
            || state == StateType::ID_LETTER
            || state == StateType::ID_DIGIT
            || state == StateType::DIG_ZERO
            || state == StateType::DIG_DIGIT;
}

#endif